//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<XEditorFrame.cpp>
///	@path	~/src/editor/xedit/
///	@date	2008/09/04
///	@brief	.

#include "editor/editor.h"

#include "editor/xedit/XEditorFrame.h"

namespace xeres {

	IMPL_IOBJECT_CLASS( XEditorFrame );

	// XEditorFrame
	XEditorFrame::XEditorFrame( FrameBase& window ) : m_window( window )
	{
		m_updateCounter = Counter::Now();
		m_updateTime = 0;
	}

	// ~XEditorFrame
	XEditorFrame::~XEditorFrame( void )
	{

	}

	// GetLayer
	Layer& XEditorFrame::GetLayer( void )
	{
		return m_layer;
	}

	// DispatchMessages
	bool XEditorFrame::DispatchMessages( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
	{
		RefWeak<IGuiForm> rootForm = m_window.GetClientForm();
		if( rootForm.IsNull() )
			return false;

		// Translate windows message to xgui message.
		bool handled = false;

		// First we check ticking update.
		if( uMsg == WM_TIMER )
		{
			// Dispatch timer event.
			if( wParam == TIMER_TICK )
			{
				Updater updater( rootForm );

				// Ticking.
				Counter next = Counter::Now();
				Counter diff = ( next - m_updateCounter );
				m_updateTime = diff.ToTime();
				float gap = (float)m_updateTime.ToMilliSecond() / 1000.f;
				rootForm->Tick( updater , gap );
				m_updateCounter = next;

				// Check if update is needed.
				if( NeedUpdate() )
				{

					Rect<int> polluted = QueryUpdate();
					// Make composition.
					Composition composition( &m_layer );
					if( composition.BeginPaint( polluted ) )
					{
						composition.graphics().SetClip( toRect(polluted) );
						// Draw form.
						rootForm->Draw( composition );
						//composition.graphics().DrawRectangle( &Gdiplus::Pen( Gdiplus::Color(255,255,255) ) , toRectF(polluted) );
						composition.EndPaint();
						// Finish update, then invalidate window.
						m_window.AcquireUpdate();
					}
					ValidateUpdate();
				}
				return true;
			}
			// No such timer.
			return false;
		}

		// Then we test if it's for none-client area.
		else if( uMsg == WM_NCACTIVATE || uMsg == WM_SETTEXT )
		{
			//incompleted;
			return false;
		}

		// Extract message detail.
		Updater updater( rootForm );
		if( TranslateMessage( hWnd , uMsg , wParam , lParam , &updater ) == INPUT_UNHANDLED )
			return false;

		// Reset local point of updater.
		updater.ResetPoint();

		// And we should check capturing states.
		if( IsCapturing() )
		{
			handled = rootForm->OnInput( updater ) == INPUT_HANDLED;
		}

		// Finally we do complicate dispatch.
		else
		{
			switch( uMsg )
			{
			case WM_SIZE:
			case WM_MOVE:
				// Handle sizing and moving messages so that in case the mouse cursor is moved out
				// of an UI control because of the window adjustment, we can properly
				// unhighlight the highlighted control.
				rootForm->ClearFocus( updater );
				handled = true;
				break;

			case WM_KILLFOCUS:
				if( rootForm->GetInputMode() )
				{
					rootForm->ClearFocus( updater );
					handled = true;
				}
				break;

			case WM_NCACTIVATE:
			case WM_ACTIVATEAPP:
				// Call OnFocusIn()/OnFocusOut() of the control that currently has the focus
				// as the application is activated/deactivated.  This matches the Windows
				// behavior.
				if( !wParam )
				{
					if( rootForm->GetInputMode() )
					{
						rootForm->ClearFocus( updater );
						handled = true;
					}
				}
				break;

				// Keyboard messages.
			case WM_KEYDOWN:
			case WM_SYSKEYDOWN:
			case WM_KEYUP:
			case WM_SYSKEYUP:
				// Mouse messages.
			case WM_MOUSEMOVE:
			case WM_LBUTTONDOWN:
			case WM_LBUTTONUP:
			case WM_MBUTTONDOWN:
			case WM_MBUTTONUP:
			case WM_RBUTTONDOWN:
			case WM_RBUTTONUP:
			case WM_XBUTTONDOWN:
			case WM_XBUTTONUP:
			case WM_LBUTTONDBLCLK:
			case WM_MBUTTONDBLCLK:
			case WM_RBUTTONDBLCLK:
			case WM_XBUTTONDBLCLK:
			case WM_MOUSEWHEEL:

			case WM_MOUSELEAVE:

				handled = rootForm->OnInput( updater ) == INPUT_HANDLED;
				break;

			case WM_CHAR:
				::MessageBeep( 0 );
				return false;
			}
		}

		if( handled && NeedUpdate() )
		{
			Rect<int> polluted = QueryUpdate();
			// Make composition.
			Composition composition( &m_layer );
			if( composition.BeginPaint( polluted ) )
			{
				composition.graphics().SetClip( toRect(polluted) );
				// Draw form.
				rootForm->Draw( composition );
				//composition.graphics().DrawRectangle( &Gdiplus::Pen( Gdiplus::Color(255,255,255) ) , toRectF(polluted) );
				composition.EndPaint();
				// Finish update, then invalidate window.
				m_window.AcquireUpdate();

				ValidateUpdate();
			}
		}
		return handled;
	}

	// Resize
	void XEditorFrame::Resize( int w , int h )
	{
		m_layer.Resize( w , h );
		RefWeak<IGuiForm> rootForm = m_window.GetClientForm();

		if( rootForm.IsValid() )
		{
			rootForm->SetSize( Pair<int>( w , h ) );
			Rect<int> rc = rootForm->GetPlacement();
			Composition composition( &m_layer );
			if( composition.BeginPaint( rc ) )
			{
				composition.graphics().SetClip( toRect(rc) );
				rootForm->Draw( composition );
				composition.EndPaint();
				m_window.AcquireUpdate();
			}
		}
	}

	// RequestUpdate
	void XEditorFrame::RequestUpdate( RefWeak<IGuiComp> comp , const Rect<int>& region )
	{
		__super::RequestUpdate( comp , region );
		m_window.AcquireUpdate();
	}

	// OnDrawBackground
	void XEditorFrame::OnDrawBackground( Composition& composition )
	{
		composition.graphics().SetCompositingMode( Gdiplus::CompositingModeSourceCopy );
		composition.graphics().FillRectangle( &Gdiplus::SolidBrush( Gdiplus::Color(0,0,0,0) ) , toRect( GetBound() ) );
		composition.graphics().SetCompositingMode( Gdiplus::CompositingModeSourceOver );
	}
	// SetSize
	bool XEditorFrame::SetSize( const Pair<int>& size )
	{
		if( __super::SetSize( size ) )
		{
			Pair<int> sz( GetSize() );
			for( size_t i = 0 , total = m_children.size() ; i < total ; ++i )
			{
				m_children[i]->SetSize( sz );
			}
			return true;
		}
		return false;
	}

} // namespace xeres
